package com.example.demo2;

/**
 * 单例模式 - 懒汉式- 线程安全(双重校验)
 * 优点:
 * 缺点:
 */
public class SingletonDemo4 {

    // 使用 volatile 保证变量的可见性,屏蔽指令重排序
    private static volatile SingletonDemo4 instance;

    private SingletonDemo4() {

    }


    /**
     * 获取单例对象的静态方法
     *
     * @return
     */
    public static SingletonDemo4 getInstance() {
        //第一次判断,如果不是null的话 就不进入强锁的代码了
        if (instance == null) {

            synchronized (SingletonDemo4.class) {
                //第二次判断 防止两个线程同时抢到锁
                if (instance == null) {

                    /**
                     * 在jvm中创建对象 会被分为3步
                     * 1.分配内存空间
                     * 2.初始化对象
                     * 3.将上面的 instance 指向分配好的内存空间
                     *
                     * 出现问题的地方 就是 (JVM可能会对上面的步骤 进行指令重排序)
                     * 默认的步骤 应该就是 1,2,3
                     * 但是jvm可能排给我们的步骤 变为 1,3,2
                     * (当第三步执行完后,B这个时候再去走到 instance == null的时候 直接返回了 instance 那么就会出现问题,
                     * 因为对象还没有被初始化,比如说里面的属性还都没有给赋值)
                     * 这个时候 如果并发比较多的话 就会出现问题  返回的 instance 是个半成品
                     * 解决的办法:
                     *  使用volatile 保证变量的可见性,屏蔽指令重排序
                     *  同时也保证多个线程修改这个变量时 线程可以拿到变量最新的值
                     *
                     */
                    instance = new SingletonDemo4();
                }

            }
        }
        return instance;
    }

}
